#include <curses.h>
#include <menu.h>
#include <string.h>
#include <stdlib.h>
#include <panel.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define CTRLD 	4
#define NLINES 10
#define NCOLS 40

struct Node
{
	PANEL *p;
	WINDOW *w;
	Node *pre, *nxt;
	char head[NCOLS];
	char body[NLINES][NCOLS];
	int st, ed, roll;
	char msg[NCOLS];
	int pos;
};
Node head, *top;

char *choices[] = {
	"ahxgw",
	"kevinlp",
	"xiehuan",
	"lvjun",
	"Exit",
	(char *)NULL,
};
char *uID[] = {
	"1000",
	"1001",
	"1002",
	"1003",
	"EXIT",
	(char *)NULL,
};
void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);

int x, y;

void win_show(Node *node)
{	int startx, starty, height, width;

	if (node == &head)
		return;
	
	getbegyx(node->w, starty, startx);
	getmaxyx(node->w, height, width);

	wclear(node->w);
	box(node->w, 0, 0);
	mvwaddch(node->w, 2, 0, ACS_LTEE); 
	mvwhline(node->w, 2, 1, ACS_HLINE, width - 2); 
	mvwaddch(node->w, 2, width - 1, ACS_RTEE); 
	
	mvwaddch(node->w, NLINES - 3, 0, ACS_LTEE); 
	mvwhline(node->w, NLINES - 3, 1, ACS_HLINE, width - 2); 
	mvwaddch(node->w, NLINES - 3, width - 1, ACS_RTEE); 
	
//	mvwprintw(node->w, 3, 1, "%s", node->body);
	int line = 3;
	int qh = node->st;
	for (line = 3; line < NLINES - 3; line++)
	{
		mvwprintw(node->w, line, 1, "%s", node->body[qh]);
		qh = (qh + 1) % (NLINES - 6);
	}
	mvwprintw(node->w, NLINES - 2, 1, "%s", node->msg);
	mvprintw(30, 2, "%s", node->head);
	
	print_in_middle(node->w, 1, 0, width, node->head, COLOR_PAIR(1));
	
	wmove(node->w, NLINES - 2, node->pos + 1);
//	wrefresh(node->w);
}

void init_wins(int i)
{
	char label[80];
	
	Node *node = new Node();
	node->w = newwin(NLINES, NCOLS, y, x);
	keypad(node->w, TRUE);
	sprintf(node->head, "%s %s", choices[i], uID[i]);
	strcpy(node->msg, "");
	node->pos = 0;
	node->st = node->ed = node->roll = 0;
	win_show(node);
	y += 3;
	x += 7;
	
	node->p = new_panel(node->w);
	node->pre = top;
	node->nxt = top->nxt;
	top->nxt = node;
	top = node;
	
	top_panel(top->p);
	update_panels();
	doupdate();
}

int main()
{	ITEM **my_items;
	int c;
	MENU *my_menu;
	int n_choices, i;
	
	/* Initialize curses */
	initscr();
	start_color();
	cbreak();
	noecho();
	keypad(stdscr, TRUE);
	init_pair(1, COLOR_RED, COLOR_BLACK);
	init_pair(2, COLOR_CYAN, COLOR_BLACK);

	/* Create items */
	n_choices = ARRAY_SIZE(choices);
	mvprintw(40, 1, "%d\n", n_choices);
	my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
	for(i = 0; i < n_choices; ++i)
		my_items[i] = new_item(choices[i], uID[i]);

	/* Crate menu */
	my_menu = new_menu((ITEM **)my_items);

	/* Create the window to be associated with the menu */
	head.w = newwin(10, 40, 4, 4);
	head.pre = head.nxt = &head;
	top = &head;
	keypad(head.w, TRUE);
	y = 2;
	x = 50;
     
	/* Set main window and sub window */
	set_menu_win(my_menu, head.w);
	set_menu_sub(my_menu, derwin(head.w, 6, 38, 3, 1));
	set_menu_format(my_menu, 5, 1);
			
	/* Set menu mark to the string " * " */
	set_menu_mark(my_menu, " * ");

	/* Print a border around the main window and print a title */
	box(head.w, 0, 0);
	print_in_middle(head.w, 1, 0, 40, "My Menu", COLOR_PAIR(1));
	mvwaddch(head.w, 2, 0, ACS_LTEE);
	mvwhline(head.w, 2, 1, ACS_HLINE, 38);
	mvwaddch(head.w, 2, 39, ACS_RTEE);
        
	/* Post the menu */
	post_menu(my_menu);
	wrefresh(head.w);
	
	head.p = new_panel(head.w);
	update_panels();
	
	attron(COLOR_PAIR(2));
	mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scoll down or up a page of items");
	mvprintw(LINES - 1, 0, "Arrow Keys to navigate (F1 to Exit)");
	attroff(COLOR_PAIR(2));
	refresh();
	
	int pos = 0;

	while((c = wgetch(top->w)) != KEY_F(1))
	{
		if (top == &head)
		{
			switch(c)
			{
				case KEY_DOWN:
					menu_driver(my_menu, REQ_DOWN_ITEM);
					pos++;
					break;
				case KEY_UP:
					menu_driver(my_menu, REQ_UP_ITEM);
					pos--;
					break;
				case KEY_NPAGE:
					menu_driver(my_menu, REQ_SCR_DPAGE);
					break;
				case KEY_PPAGE:
					menu_driver(my_menu, REQ_SCR_UPAGE);
					break;
				case 343:
					init_wins(pos);
					break;
				case 9:
					top = top->nxt;
				top_panel(top->p);
					update_panels();
					doupdate();
					win_show(top);
					break;
			}
		}
		else
		{
			switch(c)
			{
				case 9:
					top = top->nxt;
					top_panel(top->p);
					update_panels();
					doupdate();
					break;
				case 343:
					strcpy(top->body[top->ed], top->msg);
					top->ed = (top->ed + 1) % (NLINES - 6);
					if (top->roll)
						top->st = (top->st + 1) % (NLINES - 6);
					if (top->ed == 0)
						top->roll = 1;
					memset(top->msg, 0, sizeof(top->msg));
					top->pos = 0;
					win_show(top);
					break;
				case 127:
					top->msg[--top->pos] = 0;
					break;
				default:
					top->msg[top->pos++] = c;
			}
			mvprintw(40, 1, "press %d msg = %s", c, top->msg);
			win_show(top);
		}
//		wrefresh(top->w);
	}

	/* Unpost and free all the memory taken up */
	unpost_menu(my_menu);
	free_menu(my_menu);
	for(i = 0; i < n_choices; ++i)
		free_item(my_items[i]);
	endwin();
}

void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
{	int length, x, y;
	float temp;

	if(win == NULL)
		win = stdscr;
	getyx(win, y, x);
	if(startx != 0)
		x = startx;
	if(starty != 0)
		y = starty;
	if(width == 0)
		width = 80;

	length = strlen(string);
	temp = (width - length)/ 2;
	x = startx + (int)temp;
	wattron(win, color);
	mvwprintw(win, y, x, "%s", string);
	wattroff(win, color);
	refresh();
}
